// TestDataModel.h
#ifndef TESTDATAMODEL_H
#define TESTDATAMODEL_H

#include <QString>
#include <QList>
#include <QDateTime>
#include <QUuid>
#include <QDomElement>
#include <QDomDocument>

// 命名空间：区分界面层结构体，避免命名冲突
namespace TestDataModel {

/**
 * @brief 配置项模型（对应XML配置文件中的数据，全局统一缓存）
 * 存储从XML加载的所有测试数据元信息，供所有模块复用
 */
struct ConfigItem {
    QString name;         // 数据名称（唯一标识）
    QString type;         // 数据类型（U8/U16/U32/BOOL）
    quint32 portOrCommid; // 端口或ComID（UDP用端口，TRDP用ComID）
    int byteOffset;       // 字节偏移（数据在UDP包中的字节位置）
    int bitOffset;        // 位偏移（仅BOOL类型有效，0-7）
    QString description;  // 数据描述（业务字段：说明数据含义，如“设备启动状态”）
    QString defaultValue; // 默认值（业务规则：新建测试项时的默认值）
    bool isRequired;      // 是否必填（业务规则：测试时必须配置该数据）

    /**
     * @brief 序列化：将ConfigItem转换为QDomElement（用于XML存储）
     */
    QDomElement toDomElement(QDomDocument& doc) const {
        QDomElement elem = doc.createElement("ConfigItem");
        elem.setAttribute("name", name);
        elem.setAttribute("type", type);
        elem.setAttribute("PortOrCommid", portOrCommid); // XML属性名改为PortOrCommid
        elem.setAttribute("byteOffset", byteOffset);
        elem.setAttribute("bitOffset", bitOffset);
        elem.setAttribute("description", description);
        elem.setAttribute("defaultValue", defaultValue);
        elem.setAttribute("isRequired", isRequired ? "true" : "false");
        return elem;
    }

    /**
     * @brief 反序列化：从QDomElement解析ConfigItem（用于XML加载）
     */
    static ConfigItem fromDomElement(const QDomElement& elem) {
        ConfigItem item;
        item.name = elem.attribute("name");
        item.type = elem.attribute("type");
        item.portOrCommid = elem.attribute("PortOrCommid").toUInt(); // 解析为32位
        item.byteOffset = elem.attribute("byteOffset").toInt();
        item.bitOffset = elem.attribute("bitOffset").toInt();
        item.description = elem.attribute("description");
        item.defaultValue = elem.attribute("defaultValue", "0"); // 默认值默认为"0"
        item.isRequired = (elem.attribute("isRequired") == "true");
        return item;
    }
};

/**
 * @brief 测试数据项模型（输入数据/预期结果的业务模型）
 * 存储单条测试数据的完整业务属性，供测试执行、结果对比、CSV导出使用
 */
struct TestDataItem {
    QString name;         // 数据名称（与ConfigItem.name关联）
    QString type;         // 数据类型（继承自ConfigItem.type）
    quint32 portOrCommid; // 端口或ComID
    int byteOffset;       // 字节偏移（继承自ConfigItem.byteOffset）
    int bitOffset;        // 位偏移（继承自ConfigItem.bitOffset）
    QString value;        // 实际值（输入数据：用户配置值；预期结果：用户预期值）
    QString description;  // 数据描述（继承自ConfigItem.description，用于CSV导出/结果显示）

    /**
     * @brief 从ConfigItem初始化TestDataItem（新建测试项时使用）
     */
    static TestDataItem fromConfigItem(const ConfigItem& config) {
        TestDataItem item;
        item.name = config.name;
        item.type = config.type;
        item.portOrCommid = config.portOrCommid; // 继承自ConfigItem的portOrCommid
        item.byteOffset = config.byteOffset;
        item.bitOffset = config.bitOffset;
        item.value = config.defaultValue; // 默认值继承自配置项
        item.description = config.description;
        return item;
    }

    /**
     * @brief 序列化：转换为QDomElement（XML存储）
     */
    QDomElement toDomElement(QDomDocument& doc) const {
        QDomElement elem = doc.createElement("TestDataItem");
        elem.setAttribute("name", name);
        elem.setAttribute("type", type);
        elem.setAttribute("PortOrCommid", portOrCommid);
        elem.setAttribute("byteOffset", byteOffset);
        elem.setAttribute("bitOffset", bitOffset);
        elem.setAttribute("value", value);
        elem.setAttribute("description", description);
        return elem;
    }

    /**
     * @brief 反序列化：从QDomElement解析（XML加载）
     */
    static TestDataItem fromDomElement(const QDomElement& elem) {
        TestDataItem item;
        item.name = elem.attribute("name");
        item.type = elem.attribute("type");
        item.portOrCommid = elem.attribute("PortOrCommid").toUInt();
        item.byteOffset = elem.attribute("byteOffset").toInt();
        item.bitOffset = elem.attribute("bitOffset").toInt();
        item.value = elem.attribute("value");
        item.description = elem.attribute("description");
        return item;
    }
};

/**
 * @brief 测试组模型（多组输入-预期的业务模型）
 * 存储一组测试场景的完整信息，支持重试规则、组名称标识
 */
struct TestGroup {
    QString groupId;               // 组唯一ID（全局唯一，用于CSV导出/结果定位）
    QString groupName;             // 组名称（业务字段：如“正常输入场景”“边界值测试”）
    QList<TestDataItem> inputData; // 输入数据列表
    QList<TestDataItem> expectedData; // 预期结果列表
    int retryCount;                // 重试次数（业务规则：测试失败后重试次数，默认0）
    QString remark;                // 组备注（业务字段：说明该组测试目的）

    /**
     * @brief 构造函数：默认生成唯一ID和默认名称
     */
    TestGroup() {
        groupId = QUuid::createUuid().toString(QUuid::WithoutBraces); // 生成无大括号的UUID
        groupName = "默认测试组";
        retryCount = 0;
    }

    /**
     * @brief 序列化：转换为QDomElement（XML存储）
     */
    QDomElement toDomElement(QDomDocument& doc) const {
        QDomElement elem = doc.createElement("TestGroup");
        elem.setAttribute("groupId", groupId);
        elem.setAttribute("groupName", groupName);
        elem.setAttribute("retryCount", retryCount);
        elem.setAttribute("remark", remark);

        // 序列化输入数据列表
        QDomElement inputListElem = doc.createElement("InputDataList");
        for (const auto& item : inputData) {
            inputListElem.appendChild(item.toDomElement(doc));
        }
        elem.appendChild(inputListElem);

        // 序列化预期结果列表
        QDomElement expectedListElem = doc.createElement("ExpectedDataList");
        for (const auto& item : expectedData) {
            expectedListElem.appendChild(item.toDomElement(doc));
        }
        elem.appendChild(expectedListElem);

        return elem;
    }

    /**
     * @brief 反序列化：从QDomElement解析（XML加载）
     */
    static TestGroup fromDomElement(const QDomElement& elem) {
        TestGroup group;
        group.groupId = elem.attribute("groupId");
        group.groupName = elem.attribute("groupName");
        group.retryCount = elem.attribute("retryCount").toInt();
        group.remark = elem.attribute("remark");

        // 解析输入数据列表
        QDomElement inputListElem = elem.firstChildElement("InputDataList");
        QDomNodeList inputNodes = inputListElem.elementsByTagName("TestDataItem");
        for (int i = 0; i < inputNodes.size(); i++) {
            group.inputData.append(TestDataItem::fromDomElement(inputNodes.at(i).toElement()));
        }

        // 解析预期结果列表
        QDomElement expectedListElem = elem.firstChildElement("ExpectedDataList");
        QDomNodeList expectedNodes = expectedListElem.elementsByTagName("TestDataItem");
        for (int i = 0; i < expectedNodes.size(); i++) {
            group.expectedData.append(TestDataItem::fromDomElement(expectedNodes.at(i).toElement()));
        }

        return group;
    }
};

/**
 * @brief 测试案例模型（全局业务核心模型）
 * 存储测试案例的完整业务属性，是所有模块数据交互的标准格式
 */
struct TestCase {
    QString caseId;                // 案例唯一ID（全局唯一，避免名称重复）
    QString name;                  // 案例名称（用户可编辑）
    QString module;                // 所属模块（业务字段：如“通信模块”“控制模块”“电源模块”）
    QList<TestGroup> testGroups;   // 多组测试数据（核心业务数据）
    QDateTime createTime;          // 创建时间（自动记录，不可编辑）
    QDateTime updateTime;          // 最后修改时间（自动更新）
    QString creator;               // 创建人（业务字段：可选）
    QString remark;                // 案例备注（业务字段：说明案例用途、测试范围等）
    QString testResult;            // 最新测试结果（汇总所有组结果，如“所有组通过”）

    /**
     * @brief 构造函数：默认生成唯一ID和创建时间
     */
    TestCase() {
        caseId = QUuid::createUuid().toString(QUuid::WithoutBraces);
        name = "新测试案例";
        module = "未分类";
        createTime = QDateTime::currentDateTime();
        updateTime = createTime;
        creator = "未知用户";
    }

    /**
     * @brief 序列化：转换为QDomElement（XML存储）
     */
    QDomElement toDomElement(QDomDocument& doc) const {
        QDomElement elem = doc.createElement("TestCase");
        elem.setAttribute("caseId", caseId);
        elem.setAttribute("name", name);
        elem.setAttribute("module", module);
        elem.setAttribute("createTime", createTime.toString("yyyy-MM-dd HH:mm:ss"));
        elem.setAttribute("updateTime", updateTime.toString("yyyy-MM-dd HH:mm:ss"));
        elem.setAttribute("creator", creator);
        elem.setAttribute("remark", remark);
        elem.setAttribute("testResult", testResult);

        // 序列化测试组列表
        QDomElement groupsElem = doc.createElement("TestGroups");
        for (const auto& group : testGroups) {
            groupsElem.appendChild(group.toDomElement(doc));
        }
        elem.appendChild(groupsElem);

        return elem;
    }

    /**
     * @brief 反序列化：从QDomElement解析（XML加载）
     */
    static TestCase fromDomElement(const QDomElement& elem) {
        TestCase testCase;
        testCase.caseId = elem.attribute("caseId");
        testCase.name = elem.attribute("name");
        testCase.module = elem.attribute("module");
        testCase.createTime = QDateTime::fromString(elem.attribute("createTime"), "yyyy-MM-dd HH:mm:ss");
        testCase.updateTime = QDateTime::fromString(elem.attribute("updateTime"), "yyyy-MM-dd HH:mm:ss");
        testCase.creator = elem.attribute("creator");
        testCase.remark = elem.attribute("remark");
        testCase.testResult = elem.attribute("testResult");

        // 解析测试组列表
        QDomElement groupsElem = elem.firstChildElement("TestGroups");
        QDomNodeList groupNodes = groupsElem.elementsByTagName("TestGroup");
        for (int i = 0; i < groupNodes.size(); i++) {
            testCase.testGroups.append(TestGroup::fromDomElement(groupNodes.at(i).toElement()));
        }

        // 兼容旧数据：若无可视化组，默认创建1组
        if (testCase.testGroups.isEmpty()) {
            testCase.testGroups.append(TestGroup());
        }

        return testCase;
    }

    /**
     * @brief 更新最后修改时间（保存案例时调用）
     */
    void updateModifyTime() {
        updateTime = QDateTime::currentDateTime();
    }
};

/**
 * @brief 测试结果记录模型（CSV导出专用）
 * 存储单组测试的完整结果，字段与CSV列一一对应
 */
struct TestResultRecord {
    QString caseId;             // 案例ID（唯一标识）
    QString caseName;           // 测试案例名称
    QString module;             // 所属模块
    QString groupId;            // 组ID（唯一标识）
    QString groupName;          // 组名称
    QString inputVars;          // 输入变量名称及值（格式：变量1:值1,变量2:值2）
    QString outputVars;         // 输出变量名称（格式：变量1,变量2）
    QString expectedResults;    // 预期结果（格式：变量1:值1,变量2:值2）
    QString actualResults;      // 实际结果（格式：变量1:值1,变量2:值2）
    QString testTime;           // 测试时间（格式：yyyy-MM-dd HH:mm:ss）
    QString isPass;             // 是否通过（通过/不通过）
    QString remark;             // 备注（如“重试1次后通过”）

    /**
     * @brief 转换为CSV行数据（按列顺序拼接）
     */
    QString toCsvLine() const {
        // CSV格式：字段用逗号分隔，含逗号/双引号的字段用双引号包裹（处理特殊字符）
        auto escapeCsvField = [](const QString& field) {
            QString escaped = field;
            escaped.replace("\"", "\"\""); // 双引号转义为两个双引号
            if (escaped.contains(",") || escaped.contains("\"") || escaped.contains("\n")) {
                return QString("\"%1\"").arg(escaped);
            }
            return escaped;
        };

        return QString("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12")
            .arg(escapeCsvField(caseId))
            .arg(escapeCsvField(caseName))
            .arg(escapeCsvField(module))
            .arg(escapeCsvField(groupId))
            .arg(escapeCsvField(groupName))
            .arg(escapeCsvField(inputVars))
            .arg(escapeCsvField(outputVars))
            .arg(escapeCsvField(expectedResults))
            .arg(escapeCsvField(actualResults))
            .arg(escapeCsvField(testTime))
            .arg(escapeCsvField(isPass))
            .arg(escapeCsvField(remark));
    }

    /**
     * @brief 获取CSV列名（第一行）
     */
    static QString csvHeader() {
        return "案例ID,测试案例名称,所属模块,组ID,组名称,输入变量名称及值,输出变量名称,预期结果,实际结果,测试时间,是否通过,备注";
    }
};

} // namespace TestDataModel

#endif // TESTDATAMODEL_H
